From f6db9f06a43247532c19d12f16b03e3a08b68d95 Mon Sep 17 00:00:00 2001 From: robertl Date: Mon, 1 Nov 2004 02:22:51 +0000 Subject: [PATCH] Add new 'generic' xml reader, convert geo (geocaching.loc) format to use it.ZZ --- gpsbabel/geo.c | 223 +++++++++++++----------------------------- gpsbabel/xmlgeneric.c | 181 ++++++++++++++++++++++++++++++++++ gpsbabel/xmlgeneric.h | 47 +++++++++ 3 files changed, 295 insertions(+), 156 deletions(-) create mode 100644 gpsbabel/xmlgeneric.c create mode 100644 gpsbabel/xmlgeneric.h diff --git a/gpsbabel/geo.c b/gpsbabel/geo.c index 9e8eeca10..f6b4c094f 100644 --- a/gpsbabel/geo.c +++ b/gpsbabel/geo.c @@ -17,18 +17,8 @@ */ #include "defs.h" -#if !NO_EXPAT -#include -static XML_Parser psr; -#endif +#include "xmlgeneric.h" -static int in_wpt; -static int in_name; -static int in_link; -static int in_type; -static int in_cdata; -static char *cdatastr; -static char *typestr; static char *deficon = NULL; static waypoint *wpt_tmp; @@ -57,185 +47,106 @@ geo_read(void) { } #else -static void -tag_coord(const char **attrv) -{ - const char **avp = &attrv[0]; - - - while (*avp) { - if (strcmp(avp[0], "lat") == 0) { - sscanf(avp[1], "%lf", - &wpt_tmp->latitude); - } - else if (strcmp(avp[0], "lon") == 0) { - sscanf(avp[1], "%lf", - &wpt_tmp->longitude); - } - avp+=2; - } + +static xg_callback wpt_s, wpt_e; +static xg_callback wpt_link_s, wpt_link; +static xg_callback wpt_name, wpt_name_s, wpt_type, wpt_coord; + +static +xg_tag_mapping loc_map[] = { + { wpt_s, cb_start, "/loc/waypoint" }, + { wpt_e, cb_end, "/loc/waypoint" }, + { wpt_name_s, cb_start, "/loc/waypoint/name" }, + { wpt_name, cb_cdata, "/loc/waypoint/name" }, + { wpt_type, cb_cdata, "/loc/waypoint/type" }, + { wpt_link_s, cb_start, "/loc/waypoint/link" }, + { wpt_link, cb_cdata, "/loc/waypoint/link" }, + { wpt_coord, cb_start, "/loc/waypoint/coord" }, + { NULL, 0, NULL } +}; + +void wpt_s(const char *args, const char **unused) +{ +// wpt_tmp = waypt_new(); + wpt_tmp = xcalloc(sizeof(*wpt_tmp), 1); } -static void -tag_name(const char **attrv) +void wpt_e(const char *args, const char **unused) { - const char **avp = &attrv[0]; - while (*avp) { - if (strcmp(avp[0], "id") == 0) { - wpt_tmp->shortname = xstrdup(avp[1]); - } - avp+=2; - } + waypt_add(wpt_tmp); } -static void -tag_type(const char **attrv) +void wpt_name_s(const char *args, const char **attrv) { - const char **avp = &attrv[0]; - while (*avp) { - if (strcmp(avp[0], "type") == 0) { - wpt_tmp->icon_descr = xstrdup(avp[1]); - } - avp+=2; - } + const char **avp = &attrv[0]; + while (*avp) { + if (0 == strcmp(avp[0], "id")) { + wpt_tmp->shortname = xstrdup(avp[1]); + } + avp+=2; + } } -static void -tag_link(const char **attrv) +void wpt_name(const char *args, const char **unused) { - const char **avp = &attrv[0]; - while (*avp) { - if (strcmp(avp[0], "text") == 0) { - wpt_tmp->url_link_text = xstrdup(avp[1]); - } - avp+=2; - } + if (args) wpt_tmp->description = xstrdup(args); } -static void -geo_start(void *data, const char *el, const char **attr) +void wpt_link_s(const char *args, const char **attrv) { - - if (in_wpt) { - if (strcmp(el, "ele") == 0) { - wpt_tmp->altitude = atoi(attr[1]); - } - else if (strcmp(el, "name") == 0) { - tag_name(attr); - } - else if (strcmp(el, "coord") == 0) { - tag_coord(attr); - } - else if (strcmp(el, "type") == 0) { - tag_type(attr); - } - } - - if (strcmp(el, "waypoint") == 0) { - wpt_tmp = xcalloc(sizeof(*wpt_tmp), 1); - in_wpt++; - } else if (strcmp(el, "name") == 0) { - in_name++; - } else if (strcmp(el, "type") == 0) { - tag_type(attr); - in_type++; - } else if (strcmp(el, "link") == 0) { - tag_link(attr); - in_link++; - } + const char **avp = &attrv[0]; + while (*avp) { + if (0 == strcmp(avp[0], "text")) { + wpt_tmp->url_link_text = xstrdup(avp[1]); + } + avp+=2; + } +} +void wpt_link(const char *args, const char **attrv) +{ + wpt_tmp->url = xstrdup(args); } -static void -geo_end(void *data, const char *el) +void wpt_type(const char *args, const char **unused) { - if (in_cdata) { - if (in_name) { - wpt_tmp->description = xstrdup(cdatastr); - } - if (in_link) { - wpt_tmp->url = xstrdup(cdatastr); - } - in_cdata--; - memset(cdatastr,0, MY_CBUF); - } - if (strcmp(el, "waypoint") == 0) { - waypt_add(wpt_tmp); - in_wpt--; - } - else if (strcmp(el, "name") == 0) { - in_name--; - } - else if (strcmp(el, "type") == 0) { - wpt_tmp->icon_descr_is_dynamic = 1; - wpt_tmp->icon_descr = xstrdup(typestr); - memset(typestr,0, MY_CBUF); - in_type--; - } - else if (strcmp(el, "link") == 0) { - in_link--; - } + wpt_tmp->icon_descr_is_dynamic = 1; + wpt_tmp->icon_descr = xstrdup(args); } -static void -geo_cdata(void *dta, const XML_Char *s, int len) +void wpt_coord(const char *args, const char **attrv) { - char *estr; - if (in_name || in_link) { - estr = cdatastr + strlen(cdatastr); - memcpy(estr, s, len); - in_cdata++; - } - if (in_type) { - estr = typestr + strlen(typestr); - memcpy(estr, s, len); - } + const char **avp = &attrv[0]; + + while (*avp) { + if (strcmp(avp[0], "lat") == 0) { + sscanf(avp[1], "%lf", + &wpt_tmp->latitude); + } + else if (strcmp(avp[0], "lon") == 0) { + sscanf(avp[1], "%lf", + &wpt_tmp->longitude); + } + avp+=2; + } } void geo_rd_init(const char *fname) { - fd = xfopen(fname, "r", MYNAME); - - psr = XML_ParserCreate(NULL); - if (!psr) { - fatal(MYNAME ":Cannot create XML parser\n"); - } - - XML_SetElementHandler(psr, geo_start, geo_end); - cdatastr = xcalloc(MY_CBUF,1); - typestr = xcalloc(MY_CBUF,1); - XML_SetCharacterDataHandler(psr, geo_cdata); + xml_init(fname, loc_map); } void geo_read(void) { - int len; - char buf[MY_CBUF]; - - while ((len = fread(buf, 1, sizeof(buf), fd))) { - if (!XML_Parse(psr, buf, len, feof(fd))) { - fatal(MYNAME ":Parse error at %d: %s\n", - XML_GetCurrentLineNumber(psr), - XML_ErrorString(XML_GetErrorCode(psr))); - } - } - - XML_ParserFree(psr); + xml_read(); } - #endif void geo_rd_deinit(void) { - if ( cdatastr ) { - xfree(cdatastr); - } - if ( typestr ) { - xfree(typestr); - } - fclose(fd); + xml_deinit(); } void diff --git a/gpsbabel/xmlgeneric.c b/gpsbabel/xmlgeneric.c new file mode 100644 index 000000000..4e6324b48 --- /dev/null +++ b/gpsbabel/xmlgeneric.c @@ -0,0 +1,181 @@ +/* + Common utilities for XML-based formats. + + Copyright (C) 2004 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include "xmlgeneric.h" + +#ifndef NO_EXPAT + #include + static XML_Parser psr; +#endif + +static vmem_t current_tag; +static vmem_t cdatastr; +static FILE *ifd; +static xg_tag_mapping *xg_tag_tbl; + +#define MY_CBUF 4096 + +#define MYNAME "XML Reader" + +void +write_xml_entity(FILE *ofd, const char *indent, + const char *tag, const char *value) +{ + char *tmp_ent = xml_entitize(value); + fprintf(ofd, "%s<%s>%s\n", indent, tag, tmp_ent, tag); + xfree(tmp_ent); +} + +void +write_optional_xml_entity(FILE *ofd, const char *indent, + const char *tag, const char *value) +{ + if (value && *value) + write_xml_entity(ofd, indent, tag, value); +} + + +/*********************************************************************** + * These implement a simple interface for "generic" XML that + * maps reasonably close to 1:1 between XML tags and internal data + * structures. + * + * It doesn't work well for formats (like GPX) that really are "real" + * XML with extended namespaces and such, but it handles many simpler + * xml strains and insulates us from a lot of the grubbiness of expat. + */ + +xg_callback * +xml_tbl_lookup(const char *tag, xg_cb_type cb_type) +{ + xg_tag_mapping *tm; + for (tm = xg_tag_tbl; tm->tag_cb != NULL; tm++) { + if (0 == strcmp(tm->tag_name, tag) && (cb_type == tm->cb_type)) { + return tm->tag_cb; + } + } + return NULL; +} + + +static void +xml_start(void *data, const char *el, const char **attr) +{ + char *e; + char *ep; + xg_callback *cb; + + vmem_realloc(¤t_tag, strlen(current_tag.mem) + 2 + strlen(el)); + + e = current_tag.mem; + ep = e + strlen(e); + *ep++ = '/'; + strcpy(ep, el); + + memset(cdatastr.mem, 0, cdatastr.size); + + cb = xml_tbl_lookup(e, cb_start); + if (cb) { + (*cb)(NULL, attr); + } +} + +static void +xml_cdata(void *dta, const XML_Char *s, int len) +{ + char *estr; + xg_callback *cb; + + vmem_realloc(&cdatastr, 1 + len + strlen(cdatastr.mem)); + estr = (char *) cdatastr.mem + strlen(cdatastr.mem); + memcpy(estr, s, len); + estr[len] = 0; + + cb = xml_tbl_lookup(current_tag.mem, cb_cdata); + if (cb) { + (*cb)(estr, NULL); + } +} + +static void +xml_end(void *data, const char *el) +{ + char *s = strrchr(current_tag.mem, '/'); + xg_callback *cb; + + if (strcmp(s + 1, el)) { + fprintf(stderr, "Mismatched tag %s\n", el); + } + + cb = xml_tbl_lookup(current_tag.mem, cb_end); + if (cb) { + (*cb)(el, NULL); + } + *s = 0; +} + +void xml_read(void) +{ + int len; + char buf[MY_CBUF]; + + while ((len = fread(buf, 1, sizeof(buf), ifd))) { + if (!XML_Parse(psr, buf, len, feof(ifd))) { + fatal(MYNAME ":Parse error at %d: %s\n", + XML_GetCurrentLineNumber(psr), + XML_ErrorString(XML_GetErrorCode(psr))); + } + } + XML_ParserFree(psr); + +} + +void +xml_init(const char *fname, xg_tag_mapping *tbl) +{ + ifd = xfopen(fname, "r", MYNAME); + + current_tag = vmem_alloc(1,0); + *((char *)current_tag.mem) = '\0'; + + psr = XML_ParserCreate(NULL); + if (!psr) { + fatal(MYNAME ": Cannot create XML Parser\n"); + } + + cdatastr = vmem_alloc(1, 0); + *((char *)cdatastr.mem) = '\0'; + + xg_tag_tbl = tbl; + + XML_SetElementHandler(psr, xml_start, xml_end); + XML_SetCharacterDataHandler(psr, xml_cdata); +} + +void +xml_deinit(void) +{ + vmem_free(¤t_tag); + vmem_free(&cdatastr); +} + +/******************************************/ diff --git a/gpsbabel/xmlgeneric.h b/gpsbabel/xmlgeneric.h new file mode 100644 index 000000000..f01f2eefc --- /dev/null +++ b/gpsbabel/xmlgeneric.h @@ -0,0 +1,47 @@ +/* + Header for our common utilities for XML-based formats. + + Copyright (C) 2004 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + + + +typedef enum { + cb_start = 1, + cb_cdata, + cb_end, +} xg_cb_type; + +typedef void (xg_callback) (const char *, const char **); + +typedef struct xg_tag_mapping { + xg_callback *tag_cb; + xg_cb_type cb_type; + const char *tag_name; +} xg_tag_mapping; + + +void write_xml_entity(FILE *ofd, const char *indent, + const char *tag, const char *value); + +void write_optional_xml_entity(FILE *ofd, const char *indent, + const char *tag, const char *value); + +void xml_init(const char *fname, xg_tag_mapping *tbl); +void xml_read(void); +void xml_deinit(void); -- 2.30.2